package com.huiminpay.merchant.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.huiminpay.common.cache.domain.BusinessException;
import com.huiminpay.common.cache.domain.CommonErrorCode;
import com.huiminpay.common.cache.domain.PageVO;
import com.huiminpay.common.cache.util.PhoneUtil;
import com.huiminpay.common.cache.util.StringUtil;
import com.huiminpay.merchant.api.IMerchantService;
import com.huiminpay.merchant.convert.MerchantCovert;
import com.huiminpay.merchant.convert.StaffConvert;
import com.huiminpay.merchant.convert.StoreConvert;
import com.huiminpay.merchant.dto.MerchantDTO;
import com.huiminpay.merchant.dto.StaffDTO;
import com.huiminpay.merchant.dto.StoreDTO;
import com.huiminpay.merchant.entity.Merchant;
import com.huiminpay.merchant.entity.Staff;
import com.huiminpay.merchant.entity.Store;
import com.huiminpay.merchant.entity.StoreStaff;
import com.huiminpay.merchant.mapper.MerchantMapper;
import com.huiminpay.merchant.mapper.StaffMapper;
import com.huiminpay.merchant.mapper.StoreMapper;
import com.huiminpay.merchant.mapper.StoreStaffMapper;
import com.huiminpay.user.api.TenantService;
import com.huiminpay.user.api.dto.tenant.CreateTenantRequestDTO;
import com.huiminpay.user.api.dto.tenant.TenantDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.BeanUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;

@Slf4j
@org.apache.dubbo.config.annotation.Service
public class MerchantServiceImpl implements IMerchantService {

    @Resource
    MerchantMapper merchantMapper;
    @Resource
    private StoreMapper storeMapper;
    @Resource
    private StaffMapper staffMapper;

    @Resource
    private StoreStaffMapper storeStaffMapper;
    @Reference
    private TenantService tenantService;


    @Override
    public MerchantDTO queryMerchantById(Long merchantId) {
        Merchant merchant = merchantMapper.selectById(merchantId);
        MerchantDTO merchantDTO = new MerchantDTO();
        if (merchant != null) {
            BeanUtils.copyProperties(merchant, merchantDTO);
        }

        return merchantDTO;
    }

    @Override
    public MerchantDTO createMerchant(MerchantDTO merchantDTO) {
      /*   Merchant merchant = new Merchant();
        merchant.setAuditStatus("0");
        merchant.setMobile("110");
        merchant.setUsername("niuBi鹏");
        merchantMapper.insert(merchant);
        merchantDTO.setId(merchant.getId()); */
        if (merchantDTO == null) {
            throw new BusinessException(CommonErrorCode.E_100108);
        }
// 手机号非空校验
        if (StringUtils.isEmpty(merchantDTO.getMobile())) {
            throw new BusinessException(CommonErrorCode.E_100112);
        }
// 手机号合法性校验
        if (!PhoneUtil.isMatches(merchantDTO.getMobile())) {
            throw new BusinessException(CommonErrorCode.E_100109);
        }
// 联系人非空校验
        if (StringUtil.isBlank(merchantDTO.getUsername())) {
            throw new BusinessException(CommonErrorCode.E_100110);
        }
// 密码非空校验
        if (StringUtil.isBlank(merchantDTO.getPassword())) {
            throw new BusinessException(CommonErrorCode.E_100111);
        }
        LambdaQueryWrapper<Merchant> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Merchant::getMobile, merchantDTO.getMobile());
        Integer count = merchantMapper.selectCount(lqw);
        if (count > 0) {
            throw new BusinessException(CommonErrorCode.E_100113);
        }
        // 2.调用SaaS接口 添加 租户并绑定和门店 员工 商户之间的关系
        /**
         1、手机号
         2、账号
         3、密码
         4、租户类型：huimin-merchant
         5、默认套餐：huimin-merchant
         6、租户名称，同账号名
         */
        CreateTenantRequestDTO createTenantRequestDTO = new CreateTenantRequestDTO();
        createTenantRequestDTO.setMobile(merchantDTO.getMobile());
        // 租户的账号信息
        createTenantRequestDTO.setUsername(merchantDTO.getUsername());
        createTenantRequestDTO.setPassword(merchantDTO.getPassword());
        // 表示该租户类型是商户
        createTenantRequestDTO.setTenantTypeCode("huimin-merchant");// 租户类型
        // 设置租户套餐为初始化套餐餐  //套餐，根据套餐进行分配权限
        createTenantRequestDTO.setBundleCode("huimin-merchant");
        // 租户名称，和账号名一样
        createTenantRequestDTO.setName(merchantDTO.getUsername());

        // 如果租户在SaaS已经存在，SaaS直接 返回此租户的信息，否则进行添加
        TenantDTO tenantAndAccount = tenantService.createTenantAndAccount(createTenantRequestDTO);


        // 获取租户的id
        if (tenantAndAccount == null || tenantAndAccount.getId() == null) {
            throw new BusinessException(CommonErrorCode.E_200012);
        }
        // 租户的id
        Long tenantId = tenantAndAccount.getId();


        // 租户id在商户表唯一      租户  和   商户 是  一一对应的， 商户就是在  saas 中的租户
        // 根据租户id从商户表查询，如果存在记录则不允许添加商户
        Integer count1 = merchantMapper.selectCount(new LambdaQueryWrapper<Merchant>().eq(Merchant::getTenantId, tenantId));
        if (count1 > 0) {
            throw new BusinessException(CommonErrorCode.E_200017);
        }

        // 3. 设置 租户 和 商户 绑定关系
        // 将dto转成entity
        Merchant entity = MerchantCovert.INSTANCE.dto2Entity(merchantDTO);
        // 设置所对应的租户的Id
        entity.setTenantId(tenantId);  // 设置 商户 所属的租户id  注意 商户和租户是一一对应的
        // 设置审核状态0‐未申请,1‐已申请待审核,2‐审核通过,3‐审核拒绝
        entity.setAuditStatus("0");
        // 保存商户信息
        merchantMapper.insert(entity);

        // 4.新增门店  创建根门店
        StoreDTO storeDTO = new StoreDTO();
        storeDTO.setStoreName("根门店");
        storeDTO.setMerchantId(entity.getId());// 商户id 也是 租户id
        StoreDTO store = createStore(storeDTO);

        // 5.新增员工
        StaffDTO staffDTO = new StaffDTO();
        staffDTO.setMobile(merchantDTO.getMobile());// 手机号
        staffDTO.setUsername(merchantDTO.getUsername());// 账号
        // 给员工设置所属门店 此处为根门店
        staffDTO.setStoreId(store.getId());// 员所属门店id
        staffDTO.setMerchantId(entity.getId());// 商户id

        StaffDTO staff = createStaff(staffDTO);

        // 6.为门店设置管理员
        bindStaffToStore(store.getId(), staff.getId());

        // 将entity转成 dto
        MerchantDTO merchantDTONew = MerchantCovert.INSTANCE.entity2Dto(entity);
        return merchantDTONew;
    }

    @Override
    @Transactional
    public void applyMerchant(Long merchantId, MerchantDTO merchantDTO) throws BusinessException {
        if (merchantId == null || merchantDTO == null) {
            throw new BusinessException(CommonErrorCode.E_300009);
        }
        // 检验merchantid合法性，查询商户表，如果查询不到记录，认为非法
        Merchant merchant = merchantMapper.selectById(merchantId);
        if (merchant == null) {
            throw new BusinessException(CommonErrorCode.E_200002);
        }
        // 将dto转换为entity
        Merchant entity = MerchantCovert.INSTANCE.dto2Entity(merchantDTO);
        // 将必要的参数设置为entity
        entity.setId(merchant.getId());
        entity.setMobile(merchant.getMobile());// 因为资质申请的时候手机号不让改，还使用数据库中原来的手机号
        entity.setAuditStatus("1");// 审核状态1-已申请待审核
        entity.setTenantId(merchant.getTenantId());
        // 调用mapper更新商户表
        merchantMapper.updateById(entity);

    }

    /**
     * 商户下新增门店
     * @param storeDTO
     */
    @Override
    public StoreDTO createStore(StoreDTO storeDTO) throws BusinessException {
        Store store = StoreConvert.INSTANCE.dto2entity(storeDTO);
        log.info("商户下新增门店" + JSON.toJSONString(store));
        storeMapper.insert(store);
        return StoreConvert.INSTANCE.entity2dto(store);
    }

    /**
     * 商户新增员工
     * @param staffDTO
     */
    @Override
    public StaffDTO createStaff(StaffDTO staffDTO) throws BusinessException {
        // 1.校验手机号格式及是否存在
        String mobile = staffDTO.getMobile();
        if (StringUtil.isBlank(mobile)) {
            throw new BusinessException(CommonErrorCode.E_100112);
        }
        // 根据商户id和手机号校验唯一性
        if (isExistStaffByMobile(mobile, staffDTO.getMerchantId())) {
            throw new BusinessException(CommonErrorCode.E_100113);
        }
        // 2.校验用户名是否为空
        String username = staffDTO.getUsername();
        if (StringUtil.isBlank(username)) {
            throw new BusinessException(CommonErrorCode.E_100110);
        }
        // 根据商户id和账号校验唯一性
        if (isExistStaffByUserName(username, staffDTO.getMerchantId())) {
            throw new BusinessException(CommonErrorCode.E_100114);
        }
        Staff entity = StaffConvert.INSTANCE.dto2entity(staffDTO);

        staffMapper.insert(entity);
        return StaffConvert.INSTANCE.entity2dto(entity);
    }

    /**
     * 为门店设置管理员
     * @param storeId
     * @param staffId
     * @throws BusinessException
     */
    @Override
    public void bindStaffToStore(Long storeId, Long staffId) throws BusinessException {
        StoreStaff storeStaff = new StoreStaff();
        storeStaff.setStoreId(storeId);
        storeStaff.setStaffId(staffId);
        storeStaffMapper.insert(storeStaff);
    }

    /**
     * 根据租户id查询商户信息
     * @param tenantId 租户id
     * @return
     * @throws BusinessException
     */
    @Override
    public MerchantDTO queryMerchantByTenantId(Long tenantId) throws BusinessException {
        Merchant merchant = merchantMapper.selectOne(new LambdaQueryWrapper<Merchant>().eq(Merchant::getTenantId, tenantId));
        return MerchantCovert.INSTANCE.entity2Dto(merchant);
    }

    /**
     * 分页条件查询商户下门店
     * @param storeDTO
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Override
    public PageVO<StoreDTO> queryStoreByPage(StoreDTO storeDTO, Integer pageNo, Integer pageSize) {
        Page<Store> page = new Page<>(pageNo, pageSize);
        //构造查询条件
        QueryWrapper<Store> qw = new QueryWrapper<>();
        if (storeDTO!=null && storeDTO.getMerchantId() !=null) {
            qw.lambda().eq(Store::getMerchantId,storeDTO.getMerchantId());
        }
        //执行查询
        IPage<Store> storeIPage = storeMapper.selectPage(page, qw);
        //entity List 转Dto List
        List<StoreDTO> storeDTOList = StoreConvert.INSTANCE.listentity2dto(storeIPage.getRecords());
        return new PageVO<>(storeDTOList,storeIPage.getTotal(),pageNo,pageSize);

    }

    /**
     * \* 查询门店是否属于某商户
     * \* @param storeId
     * \* @param merchantId
     * \* @return
     * @param storeId
     * @param merchantId
     */
    @Override
    public Boolean queryStoreInMerchant(Long storeId, Long merchantId) {
        LambdaQueryWrapper<Store> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Store::getId,storeId ).eq(Store::getMerchantId,merchantId);
        Integer count = storeMapper.selectCount(wrapper);
        return count>0;
    }

    /**
     * 根据手机号判断员工是否已在指定商户存在
     * @param mobile 手机号
     * @return
     */
    private boolean isExistStaffByMobile(String mobile, Long merchantId) {
        LambdaQueryWrapper<Staff> lambdaQueryWrapper = new LambdaQueryWrapper<Staff>();
        lambdaQueryWrapper.eq(Staff::getMobile, mobile).eq(Staff::getMerchantId, merchantId);
        int i = staffMapper.selectCount(lambdaQueryWrapper);
        return i > 0;
    }

    /**
     * 根据账号判断员工是否已在指定商户存在
     * @param userName
     * @param merchantId
     * @return
     */
    private boolean isExistStaffByUserName(String userName, Long merchantId) {
        LambdaQueryWrapper<Staff> lambdaQueryWrapper = new LambdaQueryWrapper<Staff>();
        lambdaQueryWrapper.eq(Staff::getUsername, userName).eq(Staff::getMerchantId, merchantId);
        int i = staffMapper.selectCount(lambdaQueryWrapper);
        return i > 0;
    }

}
